package controller

import (
	"advertising/config/mysql"
	"advertising/internal/app/grpc/client"
	"advertising/internal/app/grpc/protoc/devicec"
	"advertising/internal/app/grpc/protoc/system_admin"
	"advertising/internal/models"
	"bytes"
	"context"
	"fmt"
	"io"
	"path"
	"strconv"
	"time"

	"advertising/internal/app/web/service"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"192.168.1.75/go-pkg/response"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/samber/lo"
)

const (
	FILE_CONTINUE = 1
	FILE_END      = 2
)

type Index struct{}

// Login 用户登录
func (Index) Login(c *gin.Context) {
	var params struct {
		Username    string `json:"username"`
		Password    string `json:"password"`
		CaptchaID   string `json:"captcha_id"`
		CaptchaCode string `json:"captcha_code"`
	}
	c.ShouldBindBodyWith(&params, binding.JSON)
	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		logx.Error(c.Request.Context(), "user login system admin error", logx.Any("err", clientErr.Error()))
		response.JSON(c, nil, errorx.New("登录失败", -1))
		return
	}

	var req system_admin.LoginReq
	req.Username = params.Username
	req.Password = params.Password
	req.CaptchaId = params.CaptchaID
	req.CaptchaCode = params.CaptchaCode
	res, _ := SystemAdminClient.UserLogin(c.Request.Context(), &req)
	var loginErr = errorx.Error{}
	if res.Code != 0 {
		loginErr = errorx.Error{
			Code: int(res.Code),
			Msg:  res.Msg,
		}
		response.JSON(c, nil, loginErr)
	} else {
		response.JSON(c, gin.H{
			"token": res.Data.Token,
		}, loginErr)
	}
}

// GetCaptcha 获取图形验证码
func (Index) GetCaptcha(c *gin.Context) {
	captcha, err := service.GetCaptcha()
	response.JSON(c, gin.H{
		"captcha_id":  captcha.CaptchaID,
		"captcha_img": captcha.CaptchaImg,
	}, err)
}

// FileUpload 文件上传
// file 文件
// dir 保存路径
func (Index) FileUpload(c *gin.Context) {
	file, err := c.FormFile("file")
	if err != nil {
		response.JSON(c, "", errorx.New("未获取到上传的文件", -1))
		return
	}
	logx.Info(context.Background(), "file", logx.Any("file", file.Filename))
	f, _ := file.Open()
	fmt.Println(file.Size) //50671
	AllBytes, _ := io.ReadAll(f)

	ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
	defer cancel()
	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		logx.Error(c.Request.Context(), "user login system admin error", logx.Any("err", clientErr.Error()))
		response.JSON(c, nil, errorx.New("图片上传失败", -1))
		return
	}
	fileName := helper.RandString(8) + path.Ext(file.Filename)
	req := system_admin.FileUploadReq{
		FileName:   fileName,
		Dir:        c.PostForm("dir"),
		SystemName: "advertising",
	}
	fileClient, fileClientErr := SystemAdminClient.FileUpload(context.Background())
	if fileClientErr != nil {
		logx.Error(c.Request.Context(), "file upload error", logx.Any("err", fileClientErr.Error()))
		return
	}

	var status = 0
	reader := bytes.NewReader(AllBytes)
	var totalSize = file.Size
	for {
		var buffSize int
		if totalSize >= 3*1024*1024 {
			buffSize = 3 * 1024 * 1024
		} else {
			buffSize = int(totalSize)
		}
		var buffer = make([]byte, buffSize) // 3M
		_, err := reader.Read(buffer)
		totalSize -= int64(buffSize)
		if err != nil {
			if err == io.EOF { //文件读取完毕，改变status
				status = FILE_END
			} else {
				panic(err)
			}
		} else {
			if buffSize < 3*1024*1024 || totalSize == 0 {
				status = FILE_END
			} else {
				status = FILE_CONTINUE
			}
		}
		if status == FILE_CONTINUE {
			req.File = buffer
			err = fileClient.Send(&req)
			if err != nil && err != io.EOF {
				response.JSON(c, nil, err)
				return
			}
			fmt.Println("continue")
		} else if status == FILE_END {
			req.File = buffer
			req.End = 1
			err = fileClient.Send(&req)
			if err != nil && err != io.EOF {
				response.JSON(c, nil, err)
				return
			}
			fmt.Println("end")
			break
		}
	}

	for {
		select {
		case <-fileClient.Context().Done():
			fmt.Println("context done")
			return
		case <-ctx.Done():
			fmt.Println("time time out ---")
			return
		default:
			msg, err := fileClient.Recv()
			// 消息处理
			if err == nil && msg != nil {
				response.JSON(c, gin.H{
					"file_url": msg.FileUrl,
				}, errorx.New(msg.Msg, int(msg.Code)))
				return
			} else {
				if err != io.EOF {
					logx.Error(c.Request.Context(), "file upload get error msg", logx.Any("err", err), logx.Any("msg", msg))
					response.JSON(c, nil, err)
					return
				}
			}
		}
	}
}

// 位置区域列表
func (Index) AreaLocation(c *gin.Context) {
	DeviceAdminClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		logx.Error(c.Request.Context(), "connect device admin error", logx.Any("err", clientErr.Error()))
		response.JSON(c, nil, errorx.New("系统连接错误", -1))
		return
	}

	withoutLocation := false
	if _, ok := c.GetQuery("without_location"); ok {
		withoutLocation = true
	}
	level := int64(0)
	level, _ = strconv.ParseInt(c.Query("level"), 10, 64)
	req := devicec.AreaLocationReq{
		MerchantId:      "1",
		WithoutLocation: withoutLocation,
		Level:           int32(level),
	}
	res, err := DeviceAdminClient.AreaLocation(c.Request.Context(), &req)
	if err != nil {
		response.JSON(c, nil, err)
	} else {
		response.JSON(c, res.Data, nil)
	}
}

// 所有设备列表
func (Index) AllDeviceList(c *gin.Context) {
	DeviceAdminClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		logx.Error(c.Request.Context(), "connect device admin error", logx.Any("err", clientErr.Error()))
		response.JSON(c, nil, errorx.New("系统连接错误", -1))
		return
	}

	var merchantID = c.GetString("merchant_id")
	req := devicec.AllDeviceListReq{
		MerchantId:   merchantID,
		MerchantPath: c.GetString("merchant_path"),
		DeviceTypes:  c.Query("device_types"),
		ProvinceId:   c.Query("province_id"),
		CityId:       c.Query("city_id"),
		LocationId:   c.Query("location_id"),
		DistrictId:   c.Query("district_id"),
		RobotId:      c.Query("robot_id"),
	}
	res, err := DeviceAdminClient.AllDeviceList(c.Request.Context(), &req)

	//商户允许设置的设备权限
	var MerchantDeviceList = []string{}
	mysql.NewDB().Table(models.MerchantPublishDeviceGroup{}.TableName()+" as mg").
		Joins(" inner join "+models.PublishDeviceGroup{}.TableName()+" as dg on dg.id = mg.group_id").
		Joins(" inner join "+models.PublishDevice{}.TableName()+" as device on dg.id = device.group_id").
		Where("mg.merchant_id = ?", merchantID).
		Where("dg.deleted_at = 0").
		Pluck("device.robot_name", &MerchantDeviceList)
	var DeviceList = []*devicec.AllDeviceListRsp_AllDeviceList{}
	for _, v := range res.Data {
		if lo.Contains(MerchantDeviceList, v.RobotId) {
			DeviceList = append(DeviceList, v)
		}
	}
	if err != nil {
		response.JSON(c, nil, err)
	} else {
		response.JSON(c, gin.H{
			"total": len(DeviceList),
			"list":  DeviceList,
		}, nil)
	}
}
